package cn.xy.base.server.web;

import cn.hutool.core.text.CharSequenceUtil;
import cn.xy.base.server.config.AppConfig;
import cn.xy.base.server.consts.AuthConsts;
import cn.xy.base.server.po.SysAdmin;
import cn.xy.base.server.service.SysAdminService;
import cn.xy.base.server.utils.WebContextUtil;
import cn.xy.commons.constant.Consts;
import cn.xy.commons.enums.DisableStatus;
import cn.xy.commons.util.JwtUtil;
import cn.xy.commons.web.RequestUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 管理后台业务相关拦截器
 *
 * @author xy
 */
@Slf4j
public class AdminServiceInterceptor implements HandlerInterceptor {

    private static final String INFO_CHANGE_TIPS = "账号信息已变动，请重新登陆";

    private static final String NO_LOGIN = "未登录";

    @Autowired
    private AppConfig appConfig;

    @Autowired
    private SysAdminService sysAdminService;

    @Autowired
    private RepeatSubmitService formRepeatSubmit;

    /**
     * 在请求处理之前进行调用（Controller方法调用之前）
     *
     * @param request  request
     * @param response response
     * @param handler  handler
     * @return true，如果false，停止流程，api被拦截
     */
    @Override
    public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) {
        if (!(handler instanceof HandlerMethod)) {
            WebContextUtil.setResponse(response, Consts.NOT_FOUND, "404 not found");
            return false;
        }
        // 填充AdminWebContext
        AdminWebContext.clear();
        AdminWebContext.PublicParameter publicParameter = AdminWebContext.getPublicParameter();
        String ip = RequestUtil.getRemoteAddr(request);
        publicParameter.setIp(ip);
        //忽略验证
        boolean ignoreAuth = WebContextUtil.checkIgnore(handler);
        if (ignoreAuth) {
            return true;
        }
        // 填充公共参数
        String bearToken = RequestUtil.getToken(request, AuthConsts.ADMIN_AUTHORIZATION_HEADER);
        if (CharSequenceUtil.isEmpty(bearToken)) {
            WebContextUtil.setResponse(response, Consts.NO_LOGIN_CODE, NO_LOGIN);
            return false;
        }
        publicParameter.setToken(bearToken);
        // 检查token
        Claims claims = JwtUtil.parseJwt(appConfig.getJwtSecret(), bearToken);
        if (JwtUtil.isExpired(claims, appConfig.getJwtSubject())) {
            WebContextUtil.setResponse(response, Consts.NO_LOGIN_CODE, NO_LOGIN);
            return false;
        }
        // token数据解析
        int userId = JwtUtil.getInteger(claims, SysAdminService.ID);
        int roleId = JwtUtil.getInteger(claims, SysAdminService.ROLE_ID);
        String username = JwtUtil.getString(claims, SysAdminService.USERNAME);
        String password = JwtUtil.getString(claims, SysAdminService.PASSWORD);
        // 阻止表单重复提交
        boolean result = formRepeatSubmit.prevent(userId, request, handler);
        if (result) {
            WebContextUtil.setResponse(response, Consts.ERROR_CODE, "请勿重复提交");
            return false;
        }
        // 验证登陆信息
        boolean isLogin = sysAdminService.isLogin(userId, bearToken);
        if (!isLogin) {
            WebContextUtil.setResponse(response, Consts.NO_LOGIN_CODE, "登录信息已失效，请重新登录");
            return false;
        }
        // 验证账号信息
        SysAdmin sysAdmin = sysAdminService.getById(userId);
        if (sysAdmin == null) {
            WebContextUtil.setResponse(response, Consts.NO_LOGIN_CODE, NO_LOGIN);
            return false;
        }
        if (DisableStatus.isDisable(sysAdmin.getStatus())) {
            WebContextUtil.setResponse(response, Consts.NO_LOGIN_CODE, "账号已锁定");
            return false;
        }
        if (!sysAdmin.getUsername().equals(username)) {
            WebContextUtil.setResponse(response, Consts.NO_LOGIN_CODE, INFO_CHANGE_TIPS);
            return false;
        }
        if (!sysAdmin.getPassword().equals(password)) {
            WebContextUtil.setResponse(response, Consts.NO_LOGIN_CODE, INFO_CHANGE_TIPS);
            return false;
        }
        if (sysAdmin.getRoleId() != roleId) {
            WebContextUtil.setResponse(response, Consts.NO_LOGIN_CODE, INFO_CHANGE_TIPS);
            return false;
        }
        publicParameter.setAdminId(userId);
        publicParameter.setUsername(username);
        publicParameter.setRoleId(roleId);
        sysAdminService.renewLogin(userId, bearToken);
        return true;
    }

}
